/*  */
#include "table.h"
#include "lex.h"
#include "variable.h"
#include "cstdlib/cstdlib.h"
#include "clibrary.h"
#include "type.h"
#include "parse.h"
#include <string.h>
/* global initialisation for libraries */
void Clibrary::LibraryInit(Interpreter *pc)
{

    /* define the version number macro */
    pc->versionString = MyTable::TableStrRegister(pc, PICOC_VERSION);
    Variable::VariableDefinePlatformVar(pc, NULL, "PICOC_VERSION", pc->charPtrType,
        (AnyValue*)&pc->versionString, false);

    /* define endian-ness macros */
    pc->bigEndian = ((*(char*)&pc->__ENDIAN_CHECK__) == 0);
    pc->littleEndian = ((*(char*)&pc->__ENDIAN_CHECK__) == 1);

    (pc, NULL, "BIG_ENDIAN", &pc->intType,
        (AnyValue*)&pc->bigEndian, false);
    (pc, NULL, "LITTLE_ENDIAN", &pc->intType,
        (AnyValue*)&pc->littleEndian, false);
}

/* add a library */
void Clibrary::LibraryAdd(Interpreter *pc, LibraryFunction *funcList)
{
    ParseState parser;
    char *identifier;
    ValueType *returnType;
    Value *newValue;
    void *tokens;
    char *intrinsicName = MyTable::TableStrRegister(pc, "c library");

    /* read all the library definitions */
    for (int i = 0; funcList[i].prototype != NULL; i++) {
        tokens = Lex::LexAnalyse(pc,
            (const char*)intrinsicName, funcList[i].prototype,
            strlen((char*)funcList[i].prototype), NULL);
        Lex::LexInitParser(pc, &parser, funcList[i].prototype, tokens,
            intrinsicName, true, false);
        Type::TypeParse(pc, &parser, &returnType, &identifier, NULL);
        newValue = Parse::ParseFunctionDefinition(pc, &parser, returnType, identifier);
        newValue->val->FuncDef.intrinsic = (void (*)(ParseState *, Value *, Value **, int))(funcList[i].func);
        Interpreter::HeapFreeMem(tokens);
    }
}

/* print a type to a stream without using printf/sprintf */
void Clibrary::PrintType(ValueType *typ, IOFILE *stream)
{
    switch (typ->base) {
    case kTypeVoid:
        Cstdlib::PrintStr("void", stream);
        break;
    case kTypeInt:
        Cstdlib::PrintStr("int", stream);
        break;
    case kTypeShort:
        Cstdlib::PrintStr("short", stream);
        break;
    case kTypeChar:
        Cstdlib::PrintStr("char", stream);
        break;
    case kTypeLong:
        Cstdlib::PrintStr("long", stream);
        break;
    case kTypeUnsignedInt:
        Cstdlib::PrintStr("unsigned int", stream);
        break;
    case kTypeUnsignedShort:
        Cstdlib::PrintStr("unsigned short", stream);
        break;
    case kTypeUnsignedLong:
        Cstdlib::PrintStr("unsigned long", stream);
        break;
    case kTypeUnsignedChar:
        Cstdlib::PrintStr("unsigned char", stream);
        break;
    case kTypeFP:
        Cstdlib::PrintStr("double", stream);
        break;
    case kTypeFunction:
        Cstdlib::PrintStr("function", stream);
        break;
    case kTypeMacro:
        Cstdlib::PrintStr("macro", stream);
        break;
    case kTypePointer:
        if (typ->fromType)
            PrintType(typ->fromType, stream);
        Cstdlib::PrintCh('*', stream);
        break;
    case kTypeArray:
        PrintType(typ->fromType, stream);
        Cstdlib::PrintCh('[', stream);
        if (typ->arraySize != 0)
            Cstdlib::PrintSimpleInt(typ->arraySize, stream);
        Cstdlib::PrintCh(']', stream);
        break;
    case kTypeStruct:
        Cstdlib::PrintStr("struct ", stream);
        Cstdlib::PrintStr(typ->identifier, stream);
        break;
    case kTypeUnion:
        Cstdlib::PrintStr("union ", stream);
        Cstdlib::PrintStr(typ->identifier, stream);
        break;
    case kTypeEnum:
        Cstdlib::PrintStr("enum ", stream);
        Cstdlib::PrintStr(typ->identifier, stream);
        break;
    case kTypeGotoLabel:
        Cstdlib::PrintStr("goto label ", stream);
        break;
    case kTypeType:
        Cstdlib::PrintStr("type ", stream);
        break;
    }
}

